﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using ZilLion.Service.Core.ConfigManager.Attribute;
using ZilLion.Service.Core.ConfigManager.Helper;
using ZilLion.Service.Core.ConfigManager.Interface;

namespace ZilLion.Service.Core.ConfigManager.Cache
{

    /// <summary>
    ///     配置实例缓存
    /// </summary>
    public class ConfigurationInstanceCache
    {
    
        private string GetConfigName(Type confgType)
        {
            var configName = confgType.Name;
            var zilLionConfigsectionAttribute = ConfigHelper.GetCustomAttribute<ZilLionConfigSectionAttribute>(configName);
            if (zilLionConfigsectionAttribute != null)
                configName = zilLionConfigsectionAttribute.SectionName;

            return configName;
        }

        #region cacheinstance

        public IDictionary<string, IConfigInstanceContainer> ConfigInstanceCache { get; set; } =
            new ConcurrentDictionary<string, IConfigInstanceContainer>();
        public IDictionary<Type, Type> ConfigCustomProviderCache { get; set; } =new ConcurrentDictionary<Type, Type>();


        /// <summary>
        ///     缓存所有实例的属性名，key 是属性名，Value为存在该属性名的ConfigType的List
        /// </summary>
        public IDictionary<string, IList<Type>> Propcahce { get; } = new ConcurrentDictionary<string, IList<Type>>();

        #endregion



        #region Save

        /// <summary>
        /// 保存config
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="config"></param>
        public void SaveConfig<T>(T config) where T : class
        {

            var configname = GetConfigName(typeof(T));

            if (ConfigInstanceCache.ContainsKey(configname))
            {
                ConfigInstanceCache[configname].SaveConfig();
            }

        }

        #endregion

        #region CachingConfigInstance
        private object _cachinglock=new object();
        private object _propcahcelock=new object();
        public void CachingConfigInstance<T>(string configName) where T : class, new()
        {

            #region 缓存实例
            lock(_cachinglock)
            {
                if (!ConfigInstanceCache.ContainsKey(configName))
                {

                    var configInstanceContainer = new ConfigInstanceContainer<T>();
                    ConfigInstanceCache.Add(configName, configInstanceContainer);
                }

            }

            #endregion

            #region 缓存实例的属性信息

            var configtype = typeof(T);
            var props = configtype.GetProperties().Where(x => x.CanRead);
            foreach (var prop in props)
            {
                IList<Type> typelist;
                if (Propcahce.TryGetValue(prop.Name, out typelist))
                {
                    if (typelist.All(x => x.FullName != configtype.FullName))
                        typelist.Add(configtype);
                }
                else
                {
                    lock (_propcahcelock)
                    {
                        if (!Propcahce.ContainsKey(prop.Name))
                        {
                            Propcahce.Add(prop.Name, new List<Type> { configtype });
                        }
                    }



                }
            }

            #endregion
        }

        public void CachingConfigInstance<T>() where T :  class, new()
        {

            CachingConfigInstance<T>(GetConfigName(typeof(T)));
        }

        #endregion



        #region GetConfigInstance


        public T GetConfigInstance<T>(string configName) where T : class, new()
        {
            CachingConfigInstance<T>(configName);//首先把config实例 缓存
            IConfigInstanceContainer configInstanceContainer;

            ConfigInstanceCache.TryGetValue(configName, out configInstanceContainer);

            return configInstanceContainer?.ConfigInstance as T;
        }


        public T GetConfigInstance<T>() where T : class, new()
        {
            return GetConfigInstance<T>(GetConfigName(typeof(T)));
        }
        #endregion

        #region Singleton

        private static ConfigurationInstanceCache _instance;
        private static readonly object Instancelocker = new object();


        private ConfigurationInstanceCache()
        {
        }

        public static ConfigurationInstanceCache Instance()
        {
            //没有第一重 instance == null 的话，每一次有线程进入 GetInstance()时，均会执行锁定操作来实现线程同步，
            //非常耗费性能 增加第一重instance ==null 成立时的情况下执行一次锁定以实现线程同步
            if (_instance == null)
                lock (Instancelocker)
                {
                    //Double-Check Locking 双重检查锁定
                    if (_instance == null) _instance = new ConfigurationInstanceCache();
                }
            return _instance;
        }

        public void Dispose()
        {
        }

        ~ConfigurationInstanceCache()
        {
            Dispose();
        }

        #endregion
    }
}